package com.use.utils.controller;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

@RestController
public class SegmentedDownloader {

    private static final String DOWNLOAD_URL = "http://localhost:8080/download";
    private static final String TEMP_DIR = "/Users/a123456/Downloads/temp/";
    private static final int CHUNK_SIZE_MB = 100;
    private static final int MAX_THREADS = 16;

    @RequestMapping("/req")
    public void downloadFile() throws IOException {
        String savePath = "/Users/a123456/Downloads/test.file";
        new File(TEMP_DIR).mkdirs();

        long totalSize = getFileSize();
        System.out.println("文件总大小: " + formatSize(totalSize));

        AtomicLong downloadedSize = new AtomicLong(0);
        ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);

        long chunkSize = CHUNK_SIZE_MB * 1024L * 1024L;
        long numChunks = (totalSize + chunkSize - 1) / chunkSize;

        for (int chunkId = 0; chunkId < numChunks; chunkId++) {
            long start = chunkId * chunkSize;
            long end = Math.min(start + chunkSize - 1, totalSize - 1);
            String tempFile = TEMP_DIR + "chunk-" + chunkId + ".tmp";

            File chunkFile = new File(tempFile);
            if (chunkFile.exists() && chunkFile.length() == (end - start + 1)) {
                downloadedSize.addAndGet(chunkFile.length());
                continue;
            }

            executor.execute(() -> downloadChunk(start, end, tempFile, downloadedSize, totalSize));
        }

        executor.shutdown();
        while (!executor.isTerminated()) { /* 等待所有线程完成 */ }

        mergeChunks(numChunks, savePath, totalSize);
        System.out.println("文件下载并合并完成");
    }

    private long getFileSize() throws IOException {
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpGet headRequest = new HttpGet(DOWNLOAD_URL);
            headRequest.setHeader("Authorization", "Bearer YOUR_TOKEN");

            try (CloseableHttpResponse response = client.execute(headRequest)) {
                return Long.parseLong(response.getFirstHeader("Content-Length").getValue());
            }
        }
    }

    private void downloadChunk(long start, long end, String tempFile,
                               AtomicLong downloadedSize, long totalSize) {
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpGet request = new HttpGet(DOWNLOAD_URL);
            request.setHeader("Range", "bytes=" + start + "-" + end);
            request.setHeader("Authorization", "Bearer YOUR_TOKEN");

            try (CloseableHttpResponse response = client.execute(request);
                 InputStream is = response.getEntity().getContent();
                 FileOutputStream fos = new FileOutputStream(tempFile)) {

                byte[] buffer = new byte[8 * 1024];
                int bytesRead;
                long chunkDownloadedSize = 0;

                while ((bytesRead = is.read(buffer)) != -1) {
                    fos.write(buffer, 0, bytesRead);
                    chunkDownloadedSize += bytesRead;
                }

                downloadedSize.addAndGet(chunkDownloadedSize);
                System.out.printf("Chunk %s-%s downloaded: %d bytes\n", start, end, chunkDownloadedSize);

                double progress = (downloadedSize.get() * 100.0) / totalSize;
                System.out.printf("总进度: %.2f%%\n", progress);
            }
        } catch (IOException e) {
            System.err.println("分块下载失败: " + e.getMessage());
        }
    }

    private void mergeChunks(long numChunks, String savePath, long expectedSize) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(savePath)) {
            for (int i = 0; i < numChunks; i++) {
                File chunk = new File(TEMP_DIR + "chunk-" + i + ".tmp");
                if (!chunk.exists()) {
                    throw new IOException("缺少分块文件: " + chunk.getName());
                }
                Files.copy(chunk.toPath(), fos);
                chunk.delete();
            }

            File finalFile = new File(savePath);
            if (finalFile.length() != expectedSize) {
                throw new IOException("合并后文件大小不匹配");
            }
        }
    }

    private String formatSize(long bytes) {
        if (bytes < 1024) return bytes + " B";
        int exp = (int) (Math.log(bytes) / Math.log(1024));
        String pre = "KMGTPE".charAt(exp - 1) + "i";
        return String.format("%.2f %sB", bytes / Math.pow(1024, exp), pre);
    }
}
